using Microsoft.Win32;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.Ports;
using System.Text;
using System.Threading;
using System.Windows.Forms;

namespace 串口助手
{
    public partial class Form1 : Form
    {
        private bool isOpen = false;

        private bool isRxShow = true;

        private List<byte> reciveBuffer = new List<byte>();

        private List<byte> sendBuffer = new List<byte>();

        private int reciveCount = 0;

        private int sendCount = 0;

        private Queue<byte> bufferQueue = null;

        private bool isHeadRecive = false;

        private int frameLenth = 0;

        public TransmitData transmitData;

        public event TransmitEventHandler transmitData2;

        public DecodedDataContext ddc;
        private string strRead;

        //SerialPort
        public Form1()
        {
            InitializeComponent();

            Control.CheckForIllegalCrossThreadCalls = false;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //在设计页面已经预先添加了COM1 COM2 COM3 
            //this.port_cbb.Items.Add("COM4");
            //this.port_cbb.Items.Add("COM5");

            //this.port_cbb.SelectedIndex = 2;

            //this.baud_cbb.SelectedIndex = 1;

            //this.check_cbb.SelectedIndex = 0;

            //this.databit_cbb.SelectedIndex = 3;

            //this.stopbit_cbb.SelectedIndex = 0;

            // 给发送框添加预设文本
            //  this.send_rtb.Text = "我是发送框";

            // 给接收框添加预设文本
            //  this.recive_rtb.Text = "我是接收框";

            serialLoad();
            
            // 实例化
            bufferQueue = new Queue<byte>();

           // Form2 fr2 = new Form2();
           // // 接收数据委托窗体2 ReciveData 执行显示
           // //transmitData += fr2.ReciveData;
           // // 接收数据事件窗体2 ReciveData2 执行显示
           // transmitData2 += new TransmitEventHandler(fr2.ReciveData2);
           // // 窗体2发送委托窗体1 sendBytes 执行发送
           // // fr2.useForm1Send += sendBytes;
           // // 窗体2发送事件窗体1 sendbytes2 执行发送
           // fr2.useForm1Send2 += new TransmitEventHandler(sendbytes2);
           // fr2.Show();

            ddc = new DecodedDataContext(new SimpleDecodedDataFrame());
           //// ddc = new DecodedDataContext(new MobusDecodedDataFrame());
           //// ddc.getDataFrames
        }

        private void sendbytes2(object sender, TransmitEventArgs e)
        {
            serialPort1.Write(e.data, 0, e.data.Length);
            sendCount += e.data.Length;
            sencount_tssl.Text = sendCount.ToString();
        }

        private void sendBytes(byte[] data)
        {
            serialPort1.Write(data, 0, data.Length);
            sendCount += data.Length;
            sencount_tssl.Text = sendCount.ToString();
        }

        private void serialLoad()
        {

            EncodingInfo[] encodingInfos = Encoding.GetEncodings();


            RegistryKey keyCom = Registry.LocalMachine.OpenSubKey(@"Hardware\DeviceMap\SerialComm");

            string[] sSubKeys = keyCom.GetValueNames();
            port_cbb.Items.Clear();
            foreach (var sValue in   sSubKeys)
            {
                string portName = (string)keyCom.GetValue(sValue);
                port_cbb.Items.Add(portName);
            }

            this.port_cbb.SelectedIndex = 0;

            this.baud_cbb.SelectedIndex = 1;

            this.check_cbb.SelectedIndex = 0;

            this.databit_cbb.SelectedIndex = 3;

            this.stopbit_cbb.SelectedIndex = 0;
        }

        private void sendData()
        {
            serialPort1.Write(sendBuffer.ToArray(),0,sendBuffer.Count);
            sendCount += sendBuffer.Count;
            sencount_tssl.Text = sendCount.ToString();
        }

        private void send_btn_Click(object sender, EventArgs e)
        {
            // 如果发送的数据不为空，则接收
            if (this.send_rtb.Text != "" && serialPort1.IsOpen)
            {
                Console.WriteLine(Transform.ToHexString(sendBuffer.ToArray()));
                sendData();
            }
            else
            {
                MessageBox.Show("请先输入发送数据！");

            }
        }

        private void open_btn_Click(object sender, EventArgs e)
        {
            try
            {
                if (serialPort1.IsOpen == false)
                {
                    serialPort1.PortName = port_cbb.Text;
                    serialPort1.BaudRate = Convert.ToInt32(baud_cbb.Text);
                    serialPort1.DataBits = Convert.ToInt32(databit_cbb.Text);
                    switch (check_cbb.SelectedIndex)
                    {
                        //  none  odd  even 
                        case 0:
                            serialPort1.Parity = Parity.None;
                            break;
                        case 1:
                            serialPort1.Parity = Parity.Odd;
                            break;
                        case 2:
                            serialPort1.Parity = Parity.Even;
                            break;
                        default:
                            serialPort1.Parity = Parity.None;
                            break;
                    }
                    switch (stopbit_cbb.SelectedIndex)
                    {
                        // 1 1.5 2
                        case 0:
                            serialPort1.StopBits = StopBits.One;
                            break;
                        case 1:
                            serialPort1.StopBits = StopBits.OnePointFive;
                            break;
                        case 2:
                            serialPort1.StopBits = StopBits.Two;
                            break;
                        default:
                            serialPort1.StopBits = StopBits.One;
                            break;
                    }

                    serialPort1.Open();
                    isOpen = true;
                    open_btn.Text = "关闭串口";
                    state_tssl.Text = $"打开{serialPort1.PortName}串口成功！";


                }
                else
                {
                    serialPort1.Close();
                    isOpen = false;
                    open_btn.Text = "打开串口";
                    state_tssl.Text = $"关闭{serialPort1.PortName}串口成功！";
                }
            }
            catch (Exception ex)
            {
                state_tssl.Text = $"打开{serialPort1.PortName}串口异常！";
                MessageBox.Show(ex.ToString()+serialPort1.PortName.ToString());
            }
        }

        private void serialPort1_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            if (isRxShow == false) return;
            // 1,需要读取有效的数据 BytesToRead
            byte[] dataTemp = new byte[serialPort1.BytesToRead];
            serialPort1.Read(dataTemp,0,dataTemp.Length);

            reciveBuffer.AddRange(dataTemp);

            reciveCount += dataTemp.Length;

            //?. = 如果transmitData !=null
           // transmitData?.Invoke(dataTemp);
           // transmitData2?.Invoke(this, new TransmitEventArgs { data = dataTemp });
            this.Invoke(new EventHandler(delegate
            {
                // 显示接收数据的长度
                recivecount_tssl.Text = reciveCount.ToString();
                if (startData_chb.Checked == false)
                {
                    if (!recivehex_chb.Checked)
                    {
                        // 2, 编码格式的选择
                        string str = Encoding.GetEncoding("gb2312").GetString(dataTemp);
                        // 3，0x00 -> \0 结束 不会显示
                        str = str.Replace("\0", "\\0");

                        recive_rtb.AppendText(str);

                        // recive_rtb.AppendText(Encoding.GetEncoding("gb2312").GetString(dataTemp).Replace("\0", "\\0"));
                    }
                    else
                    {
                        //  十六进制是选中的状态下
                        recive_rtb.AppendText(Transform.ToHexString(dataTemp, " "));
                    }
                }
                else
                {
                    // 解析数据 queue

                    foreach (byte item in dataTemp)
                    {
                        // 入列
                        bufferQueue.Enqueue(item);
                    }
                    // 获取帧数据
                    byte[] frameData = ddc.getDataFrames(bufferQueue);

                    if (frameData != null)
                    {
                        Console.WriteLine($"show the data in frameData{Transform.ToHexString(frameData)}");
                        data_txb.Text = Transform.ToHexString(frameData);
                        data1_txb.Text = String.Format("{0:X2}", frameData[2]);
                        data2_txb.Text = String.Format("{0:X2}", frameData[3]);
                        data3_txb.Text = String.Format("{0:X2}", frameData[4]);
                        data4_txb.Text = String.Format("{0:X2}", frameData[5]);

                        for (int i = 0; i < frameData.Length; i++)
                        {
                            bufferQueue.Dequeue();
                        }
                    }
#if old

                    // 解析获取帧头
                    if (isHeadRecive == false)
                    {

                        foreach (byte item in bufferQueue.ToArray())
                        {
                            if (item != 0x7f)
                            {
                                // 出列
                                bufferQueue.Dequeue();
                                Console.WriteLine("not 0x7f, Dequeue !!");
                            }
                            else
                            {
                                // get 0x7f from bufferQueue
                                isHeadRecive = true;
                                Console.WriteLine("0x7f is recived !!");
                                break;
                            }
                        }
                    }

                    if (isHeadRecive == true)
                    {
                        // 判断有数据帧长度
                        if (bufferQueue.Count >= 2)
                        {
                            Console.WriteLine(DateTime.Now.ToLongTimeString());
                            Console.WriteLine($"show the data in bufferQueue{Transform.ToHexString(bufferQueue.ToArray())}");
                            Console.WriteLine($"frame lenth ={String.Format("{0:X2}", bufferQueue.ToArray()[1])}");
                            frameLenth = bufferQueue.ToArray()[1];
                            // 一帧完整的数据长度判断，不代表数据是正确的
                            if(bufferQueue.Count>=1+1+frameLenth+2)
                            {
                                byte[] frameBuffer = new byte[1 + 1 + frameLenth + 2];
                                Array.Copy(bufferQueue.ToArray(), 0, frameBuffer, 0, frameBuffer.Length);
                                if(crc_chech(frameBuffer))
                                {
                                    Console.WriteLine("frame is check ok,pick it");
                                    data_txb.Text = Transform.ToHexString(frameBuffer);
                                    data1_txb.Text = String.Format("{0:X2}", frameBuffer[2]);
                                    data2_txb.Text = String.Format("{0:X2}", frameBuffer[3]);
                                    data3_txb.Text = String.Format("{0:X2}", frameBuffer[4]);
                                    data4_txb.Text = String.Format("{0:X2}", frameBuffer[5]);

                                }
                                else
                                {
                                    // 无效数据
                                    Console.WriteLine("bad frame, drop it");
                                    
                                }


                                for(int i=0; i<1 + 1+frameLenth+2;i++)
                                {
                                    bufferQueue.Dequeue();
                                }

                                isHeadRecive = false;
                            }
                        }
                        //接续接收数据
                    }
#endif
                }
            }));
        }

        private bool crc_chech(byte[] frameBuffer)
        {
            /*大端模式: 是指数据的高字节保存在内存的低地址中，
             * 而数据的低字节保存在内存的高地址中，这样的存储
             * 模式有点儿类似于把数据当作字符串顺序处理：地址
             * 由小向大增加，而数据从高位往低位放；这和我们的
             * 阅读习惯一致。
             * 
             * 小端模式: 是指数据的高字节保存在内存的高地址中，
             * 而数据的低字节保存在内存的低地址中，这种存储模
             * 式将地址的高低和数据位权有效地结合起来，高地址
             * 部分权值高，低地址部分权值低。
             */
            bool ret = false;

            byte[] temp = new byte[frameBuffer.Length-2];
            Array.Copy(frameBuffer, 0, temp, 0, temp.Length);
            byte[] crcdata = DataCheck.DataCrc16_Ccitt(temp, DataCheck.BigOrLittle.BigEndian);
            if (crcdata[0] == frameBuffer[frameBuffer.Length - 2] &&
                crcdata[1]== frameBuffer[frameBuffer.Length-1])
            {
                // check ok
                ret = true;
            }

            return ret;

        }

        private void stop_btn_Click(object sender, EventArgs e)
        {
            if (isRxShow == true)
            {
                isRxShow = false;
                stop_btn.Text = "取消暂停";
            }
            else
            {
                isRxShow = true;
                stop_btn.Text = "暂停";
            }
        }

        private void recivehex_chb_CheckedChanged(object sender, EventArgs e)
        {
            if (recive_rtb.Text == "") return;
            if (recivehex_chb.Checked)
            {
                recive_rtb.Text = Transform.ToHexString(reciveBuffer.ToArray()," ");
            }
            else
            {
                recive_rtb.Text = Encoding.GetEncoding("gb2312").GetString(reciveBuffer.ToArray()).Replace("\0","\\0");
            }
        }

        private void clear_btn_Click(object sender, EventArgs e)
        {
            reciveBuffer.Clear();
            reciveCount = 0;
            recivecount_tssl.Text = "0";
            recivecount_tssl.Text = "";
            recive_rtb.Text = "";
        }

        private void autoclear_chb_CheckedChanged(object sender, EventArgs e)
        {
            if (autoclear_chb.Checked)
            {


                timer1.Start();
            }
            else
            {
                timer1.Stop();
            }
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            if (recive_rtb.Text.Length > 4096)
            {
                reciveBuffer.Clear();
                recive_rtb.Text = "";
                recivecount_tssl.Text = "";
            }
        }

        private void send_rtb_Leave(object sender, EventArgs e)
        {
            if (sendhex_chb.CheckState == CheckState.Checked)
            {
                if (DataEncoding.IsHexString(send_rtb.Text.Replace(" ", "")))
                {
                    sendBuffer.Clear();
                    sendBuffer.AddRange(Transform.ToBytes(send_rtb.Text.Replace(" ", "")));

                }
                else
                {
                    MessageBox.Show("请输入正确的十六进制数据！！");
                    send_rtb.Select();
                }
            }
            else
            {
                sendBuffer.Clear();
                sendBuffer.AddRange(Encoding.GetEncoding("gb2312").GetBytes(send_rtb.Text));
            }
        }

        private void send_rtb_TextChanged(object sender, EventArgs e)
        {
            // 十六进制切换 会出现问题  这问题就是0x00 转换
        }

        private void sendhex_chb_CheckedChanged(object sender, EventArgs e)
        {
            if (send_rtb.Text == "") return;

            if (sendhex_chb.Checked == true)
            {
                send_rtb.Text = Transform.ToHexString(sendBuffer.ToArray(), " ");
            }
            else 
            { 
                send_rtb.Text = Encoding.GetEncoding("gb2312").GetString(sendBuffer.ToArray()).Replace("\0","\\0");

            }
        }

        private void sendclear_btn_Click(object sender, EventArgs e)
        {
            sendBuffer.Clear();

            send_rtb.Text = "";

            sendCount = 0;

            sencount_tssl.Text = "0";
        }

        private void cleancount_tssl_Click(object sender, EventArgs e)
        {
            // 清空发送
            sendBuffer.Clear();
            sendCount = 0;
            sencount_tssl.Text = "0";
            // 清空接收
            reciveBuffer.Clear();
            recive_rtb.Text = "";
            recivecount_tssl.Text = "0";
        }

        private void RTS_chb_CheckedChanged(object sender, EventArgs e)
        {
            if (RTS_chb.CheckState == CheckState.Checked)
            {
                serialPort1.RtsEnable = true;
            }
            else
            {
                serialPort1.RtsEnable = false;
            }
        }

        private void DTR_chb_CheckedChanged(object sender, EventArgs e)
        {
            if (DTR_chb.CheckState == CheckState.Checked)
            {
                serialPort1.DtrEnable = true;
            }
            else
            {
                serialPort1.DtrEnable = false;
            }
        }

        private void autosend_chb_CheckedChanged(object sender, EventArgs e)
        {
            // 串口未打开
            if(serialPort1.IsOpen==false && autosend_chb.CheckState == CheckState.Checked)
            {
                autosend_chb.CheckState = CheckState.Unchecked;
                if(timer2!=null)
                {
                    timer2.Enabled = false;
                    timer2.Stop();
                   // timer2 = null;
                }

                MessageBox.Show("发送失败，串口未打卡");
                return;
            }
            // 串口打开
            if (serialPort1.IsOpen == true && autosend_chb.CheckState == CheckState.Checked)
            {
                autotimer_txb.Enabled = false;
                send_btn.Enabled = false;
                int i = Convert.ToInt32(autotimer_txb.Text);
                if (i < 10 || i>60*1000)
                {
                    i = 1000;
                    autotimer_txb.Text = "1000";
                    MessageBox.Show("自动发送数据的周期范围是10-60000毫秒", "警告");
                }
                timer2.Interval = i;
                timer2.Start();

            }
            else
            {
                send_btn.Enabled = true;
                autotimer_txb.Enabled = true;
                if(timer2!=null)
                {
                    timer2.Stop();
                    //timer2 = null;
                }
            }

        }

        private void timer2_Tick(object sender, EventArgs e)
        {
            // 如果发送的数据不为空，则接收
            if (this.send_rtb.Text != "" && serialPort1.IsOpen)
            {
                Console.WriteLine(Transform.ToHexString(sendBuffer.ToArray()));
                sendData();
            }
            else
            {
                state_tssl.Text = "请先输入发送数据！";
                Console.WriteLine("请先输入发送数据！");
            }
        }

        private void xzlj_btn_Click(object sender, EventArgs e)
        {
            FolderBrowserDialog fbDialog = new FolderBrowserDialog();
            if(fbDialog.ShowDialog()==DialogResult.OK)
            {
                reciveflie_txb.Text = fbDialog.SelectedPath;
            }
        }

        private void bcsj_btn_Click(object sender, EventArgs e)
        {
            if(recive_rtb.Text=="")
            {
                return;
            }

            string fileName = reciveflie_txb.Text + "\\" + DateTime.Now.ToString("yyyyMMddhhmmss") + ".txt";

            StreamWriter sw = new StreamWriter(fileName);
            sw.Write(recive_rtb.Text);
            sw.Flush();
            sw.Close();
            MessageBox.Show("保存成功！");
        }

        /// <summary>
        /// 加载文本到发送窗
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void dkwj_btn_Click(object sender, EventArgs e)
        {
            OpenFileDialog ofDialog = new OpenFileDialog();
            ofDialog.Title = "请选择文件";
            ofDialog.Filter = "文本文件(*.txt)|*.txt";
            ofDialog.RestoreDirectory = true;
            if(ofDialog.ShowDialog()==DialogResult.OK)
            {
                string fileName = ofDialog.FileName;
                // string select 
                sendfile_txb.Text = fileName;
                StreamReader sr = new StreamReader(fileName, Encoding.GetEncoding("gb2312"));
                strRead = sr.ReadToEnd();
                send_rtb.Text = strRead;
                sr.Close();
            }
        }

        private void fswj_btn_Click(object sender, EventArgs e)
        {
            if(strRead=="")
            {
                MessageBox.Show("请先选择文件！");
                return;
            }

            try
            {
                byte[] data = Encoding.GetEncoding("gb2312").GetBytes(strRead);
                sendCount += data.Length;
                sencount_tssl.Text = sendCount.ToString();
                int pagenum = data.Length / 4096;
                int remaind = data.Length % 4096;
                for(int i=0; i<pagenum;i++)
                {
                    serialPort1.Write(data, (i * 4096), 4096);
                    Thread.Sleep(10);
                }
                if(remaind>0)
                {
                    serialPort1.Write(data, (pagenum * 4096), remaind);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("发送数据失败" + ex.Message.ToString(),"错误");
            }
        }
    }
}
